/*
 * User: rant
 * Date: 31/12/2006
 *
 *
 */
package laMalinche.rete.nodes.editing;

import laMalinche.DerivationAdviser;
import laMalinche.editableContext.AboutToChangeManager;
import laMalinche.editableContext.BasicAboutToChangeManager;
import laMalinche.rete.ReteRoot;
import laMalinche.rete.rule.*;
import laMalinche.ruleTailing.BusinessRelevantPropertyListener;
import org.jetbrains.annotations.NotNull;

import java.util.*;

/**
 *
 */
public class EditableContextReteRoot extends ReteRoot implements DerivationListener {
	private AboutToChangeManager aboutToChangeManager;
	private final BasicAboutToChangeManager myAboutToChangeManager = new BasicAboutToChangeManager();
	private final Set<BusinessRelevantPropertyListener> relevantPropertyListeners = new HashSet<BusinessRelevantPropertyListener>();

	public EditableContextReteRoot() {
        setAboutToChangeManager(myAboutToChangeManager);
	}

	/**
	 this is part of the contract with AboutToChangeManager
	 inEditing represents fields that will be edited next form
	 @param inEditing
	 */
	public void futureEditingProcess(Set<String> inEditing) {
		Map<BusinessRuleType, Set<String>> activeProperties = new HashMap<BusinessRuleType, Set<String>>();
		final Map<BusinessRuleType, Map<String, ProductionRule>> readOnlyRuleMap = getRuleMap().getReadOnlyRuleMap();
		// all tailing conditions shuld be informers
		for (BusinessRuleType ruleType : BusinessRuleType.values()) {
			Set<String> willBeActiveForType = new HashSet<String>();
			if (ruleType.isEditableContextSensitive()) {
				final Map<String, ProductionRule> map = readOnlyRuleMap.get(ruleType);
				final Collection<ProductionRule> rules = map.values();
				for (ProductionRule rule : rules) {
					final WillBeActiveProductionRuleVisitor productionRuleVisitor = new WillBeActiveProductionRuleVisitor(inEditing);
					rule.accept(productionRuleVisitor);
					final Set<String> willBeActiveForRule = productionRuleVisitor.getWillBeActiveForRule();
					willBeActiveForType.addAll(willBeActiveForRule);
				}
				activeProperties.put(ruleType, willBeActiveForType);
			}
		}
		Set<BusinessRelevantPropertyListener> businessRelevantPropertyListeners = getRelevantPropertyListeners();
		for (BusinessRelevantPropertyListener listener : businessRelevantPropertyListeners) {
			listener.bussinessRelevantPropertyChanged(activeProperties);
		}
	}



	private Set<BusinessRelevantPropertyListener> getRelevantPropertyListeners() {
		return relevantPropertyListeners;
	}

	/*
	listern to future activated properties information
	 */
	public void addRelevantPropertyListener(BusinessRelevantPropertyListener listener) {
		relevantPropertyListeners.add(listener);
	}

	@Override
	public void add(@NotNull ProductionRule rule) {
		super.add(rule);
		final BusinessRuleType ruleType = rule.getProductionRuleType();
		if (BusinessRuleType.derivedInSession.equals(ruleType)) {
			final DerivationRule derivationRule = ((DerivationRule) rule);
			((DerivationAdviser) rule.getAction()).addDerivationListener(this);
			final String derivedFieldOgnl = derivationRule.getDerivedFieldOgnl();
			myAboutToChangeManager.addToAboutToChange(derivedFieldOgnl);
		}
	}

	public AboutToChangeManager getAboutToChangeManager() {
		return aboutToChangeManager;
	}

	public void setAboutToChangeManager(AboutToChangeManager aboutToChangeManager) {
		((BasicAboutToChangeManager) aboutToChangeManager).setReteRoot(this);
		if (this.aboutToChangeManager != null) {
			this.aboutToChangeManager.addAboutToChangeManager(aboutToChangeManager);
		} else {
			this.aboutToChangeManager = aboutToChangeManager;
		}
	}

	public void derivationRuleConcluded(final String fieldOgnl, final boolean executed) {
		if (executed) {
			myAboutToChangeManager.removeAboutToChange(fieldOgnl);
		} else {
			myAboutToChangeManager.addAboutToChange(fieldOgnl);
		}
	}
}